#
# CMakeLists.txt file for NimbleSM
#

Cmake_minimum_required(VERSION 3.1)
project(NimbleSM CXX C Fortran)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

enable_testing()

set(SRC_DIR ${CMAKE_SOURCE_DIR}/src)

SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")

SET(HAVE_DARMA OFF CACHE BOOL "Whether to use DARMA")
SET(USE_PURE_MPI OFF CACHE BOOL "Whether to use Pure MPI (no Trilinos)")
SET(HAVE_BVH OFF CACHE BOOL "Whether to use BVH")
SET(HAVE_TRILINOS OFF CACHE BOOL "Whether to use Trilinos")
SET(HAVE_QTHREADS OFF CACHE BOOL "Whether to use QThreads")
SET(HAVE_KOKKOS OFF CACHE BOOL "Whether to use Kokkos")
SET(HAVE_NIMBLE_EXTRAS OFF CACHE BOOL "Whether to use NimbleSM Extras")
SET(NIMBLE_NVIDIA_BUILD OFF CACHE BOOL "Whether to use Nvidia build")

if (HAVE_DARMA)
  find_package(DARMA REQUIRED COMPONENTS ${DARMA_BACKEND_PKG})
  if (DARMA_FOUND)
    MESSAGE("-- Compiling with DARMA:")
    MESSAGE("       DARMA_BACKEND_CXX_COMPILER: ${DARMA_BACKEND_CXX_COMPILER}")
    MESSAGE("       DARMA_BACKEND_CXX_FLAGS: ${DARMA_BACKEND_CXX_FLAGS}")
    MESSAGE("       DARMA_INCLUDE_DIRS: ${DARMA_INCLUDE_DIRS}")
    MESSAGE("       DARMA_LIBRARIES: ${DARMA_LIBRARIES}")
    include_directories( ${DARMA_INCLUDE_DIRS} )
    set (CMAKE_CXX_COMPILER ${DARMA_BACKEND_CXX_COMPILER})
    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DARMA_BACKEND_CXX_FLAGS}")
    ADD_DEFINITIONS(-DNIMBLE_HAVE_DARMA)
    SET(NIMBLE_HAVE_DARMA TRUE)
  endif()
else()
  MESSAGE("-- DARMA is NOT enabled.")
  SET(NIMBLE_HAVE_DARMA FALSE)
  SET(NIMBLE_HAVE_CHARM FALSE)
  SET(DARMA_BACKEND_LIBRARIES)
endif()

# Optional DARMA dependencies
#[[
IF(HAVE_DARMA)
  ADD_DEFINITIONS(-DNIMBLE_HAVE_DARMA)
  SET(NIMBLE_HAVE_DARMA TRUE)
  if (DARMA_BACKEND_PKG)
    find_package (${DARMA_BACKEND_PKG}
        PATHS ${DARMA_BACKEND_ROOT})
    if (NOT ${DARMA_BACKEND_PKG}_FOUND)
      message (FATAL_ERROR
        "Error: DARMA backend package could not be found; use "
        "${DARMA_BACKEND_PKG}_DIR= to specify path to "
        "${DARMA_BACKEND_PKG}Config.cmake file")
    endif ()
    #set (CMAKE_CXX_COMPILER ${DARMA_BACKEND_CXX_COMPILER})
    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DARMA_BACKEND_CXX_FLAGS}")
    MESSAGE("frontend dir: ${DARMA_FRONTEND_INCLUDE_DIR}")
    include_directories( ${DARMA_FRONTEND_INCLUDE_DIR} ${DARMA_BACKEND_INCLUDE_DIRS} )
    link_directories( ${DARMA_BACKEND_LIBRARY_DIRS} )
  else()  # not using cmake package
    message(FATAL_ERROR
      "Specify the DARMA backend package using -DDARMA_BACKEND_PKG=")
  endif()
  IF(${DARMA_BACKEND_PKG} STREQUAL DarmaCharmBackend)
    ADD_DEFINITIONS(-DNIMBLE_HAVE_CHARM)
    SET(NIMBLE_HAVE_CHARM TRUE)
  ENDIF()
  MESSAGE("-- Compiling with DARMA:")
  MESSAGE("       DARMA_BACKEND_PKG: ${DARMA_BACKEND_PKG}")
  MESSAGE("       DARMA_BACKEND_CXX_COMPILER: ${DARMA_BACKEND_CXX_COMPILER}")
  MESSAGE("       DARMA_BACKEND_CXX_FLAGS: ${DARMA_BACKEND_CXX_FLAGS}")
  MESSAGE("       DARMA_BACKEND_INCLUDE_DIRS: ${DARMA_BACKEND_INCLUDE_DIRS}")
  MESSAGE("       DARMA_BACKEND_LIBRARY_DIRS: ${DARMA_BACKEND_LIBRARY_DIRS}")
  MESSAGE("       DARMA_BACKEND_LIBRARIES: ${DARMA_BACKEND_LIBRARIES}")
ELSE()
  MESSAGE("-- DARMA is NOT enabled.")
  SET(NIMBLE_HAVE_DARMA FALSE)
  SET(NIMBLE_HAVE_CHARM FALSE)
  SET(DARMA_BACKEND_LIBRARIES)
ENDIF()
#]]

# Optional dependency for pure MPI build (no Trilinos)
IF(USE_PURE_MPI OR HAVE_NIMBLE_EXTRAS)
  ADD_DEFINITIONS(-DNIMBLE_HAVE_MPI)
  SET(NIMBLE_HAVE_MPI TRUE)
  MESSAGE("-- Compiling with MPI")
  FIND_PACKAGE(MPI REQUIRED)
  include_directories(${MPI_CXX_INCLUDE_DIRS})
  add_definitions(${MPI_CXX_COMPILE_DEFINITIONS})
  set(CMAKE_CXX_COMPILER_FLAGS ${CMAKE_CXX_COMPILER_FLAGS} ${MPI_CXX_COMPILE_OPTIONS})
  set(CMAKE_CXX_LINKER_FLAGS ${CMAKE_CXX_LINKER_FLAGS} ${MPI_CXX_LINK_FLAGS})
ENDIF()

# Optional BVH dependency
IF(HAVE_BVH)
  ADD_DEFINITIONS(-DNIMBLE_HAVE_BVH)
  IF(BVH_DEBUG_LEVEL)
    ADD_DEFINITIONS(-DBVH_DEBUG_LEVEL=${BVH_DEBUG_LEVEL})
  ENDIF()
  SET(NIMBLE_HAVE_BVH TRUE)
  SET(bvh_DIR CACHE PATH "Path to BVH install directory")
  FIND_PACKAGE(bvh REQUIRED)
  MESSAGE("-- Compiling with BVH:")
  MESSAGE("       TinyMath_DIR: ${TinyMath_DIR}")
  MESSAGE("       BVH_DIR: ${bvh_DIR}")
  IF(NIMBLE_HAVE_MPI)
    MESSAGE("       Using parallel collision detection (NIMBLE_HAVE_MPI=ON)")
  ELSE()
    MESSAGE("       Using only serial collision detection (NIMBLE_HAVE_MPI=OFF)")
  ENDIF()
  set(bvh_LIBS bvh::bvh)
ELSE()
  MESSAGE("-- BVH is NOT enabled.")
  SET(NIMBLE_HAVE_BVH FALSE)
  set(bvh_LIBS)
ENDIF()

if (NIMBLE_NVIDIA_BUILD)
  enable_language(CUDA)
  add_definitions(-DNIMBLE_NVIDIA_BUILD)
  set(CMAKE_POSITION_INDEPENDENT_CODE ON)
  set(CMAKE_CUDA_SEPARABLE_COMPILATION ON)
  set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -rdc=true --expt-extended-lambda")
  set(CMAKE_LD_FLAGS "${CMAKE_LD_FLAGS} -rdc=true")
endif()

# Optional Trilinos dependencies
IF(HAVE_TRILINOS OR HAVE_NIMBLE_EXTRAS)
  set(NIMBLE_TRILINOS_COMPONENTS KokkosCore Tpetra)
  if(NOT HAVE_NIMBLE_EXTRAS) # exodus from Trilinos
    set(NIMBLE_TRILINOS_COMPONENTS ${NIMBLE_TRILINOS_COMPONENTS} SEACASExodus)
  else()
    set(NIMBLE_TRILINOS_COMPONENTS ${NIMBLE_TRILINOS_COMPONENTS} Sacado)
  endif()
  ADD_DEFINITIONS(-DNIMBLE_HAVE_TRILINOS)
  SET(NIMBLE_HAVE_TRILINOS TRUE)
  ADD_DEFINITIONS(-DNIMBLE_HAVE_KOKKOS)
  SET(NIMBLE_HAVE_KOKKOS TRUE)
  ADD_DEFINITIONS(-DNIMBLE_HAVE_EXODUS)
  SET(NIMBLE_HAVE_EXODUS TRUE)
  SET(Trilinos_DIR CACHE PATH "Path to Trilinos install directory")
  SET(CMAKE_PREFIX_PATH ${Trilinos_DIR} ${CMAKE_PREFIX_PATH})
  FIND_PACKAGE(Trilinos REQUIRED COMPONENTS ${NIMBLE_TRILINOS_COMPONENTS})
  MESSAGE("-- Compiling with Trilinos:")
  MESSAGE("       Trilinos_DIR: ${Trilinos_DIR}")
  MESSAGE("       Trilinos_VERSION: ${Trilinos_VERSION}")
  MESSAGE("       Trilinos_TPL_LIST: ${Trilinos_TPL_LIST}")
#  MESSAGE("       Trilinos_PACKAGE_LIST: ${Trilinos_PACKAGE_LIST}")
#  MESSAGE("       Trilinos_TPL_INCLUDE_DIRS: ${Trilinos_TPL_INCLUDE_DIRS}")
#  MESSAGE("       Trilinos_TPL_LIBRARIES: ${Trilinos_TPL_LIBRARIES}")
#  MESSAGE("       Trilinos_TPL_LIBRARY_DIRS: ${Trilinos_TPL_LIBRARY_DIRS}")
#  MESSAGE("       Trilinos_BUILD_SHARED_LIBS: ${Trilinos_BUILD_SHARED_LIBS}")
#  MESSAGE("       Trilinos_CXX_COMPILER_FLAGS: ${Trilinos_CXX_COMPILER_FLAGS}")
#  MESSAGE("       Trilinos_INCLUDE_DIRS: ${Trilinos_INCLUDE_DIRS}")
#  MESSAGE("       Trilinos_LIBRARY_DIRS: ${Trilinos_LIBRARY_DIRS}")
  include_directories(${Trilinos_INCLUDE_DIRS} ${Trilinos_TPL_INCLUDE_DIRS})
  link_directories(${Trilinos_LIBRARY_DIRS} ${Trilinos_TPL_LIBRARY_DIRS})
  MESSAGE("       Trilinos_LIBRARIES: ${Trilinos_LIBRARIES}")
  set(CMAKE_LD_FLAGS "${CMAKE_LD_FLAGS} ${Trilinos_LD_FLAGS}")
ELSE()
  MESSAGE("-- Trilinos is NOT enabled.")
  SET(NIMBLE_HAVE_TRILINOS FALSE)
ENDIF()

if(HAVE_NIMBLE_EXTRAS)
  SET(NIMBLE_EXTRAS_DIR "" CACHE PATH "Path to Nimble Extras")
  if(NIMBLE_EXTRAS_DIR)
    include(${NIMBLE_EXTRAS_DIR}/CMakeLists.txt)
    message("-- Compiling with Nimble Extras:")
    message("       NIMBLE_EXTRAS_DIR: ${NIMBLE_EXTRAS_DIR}")
    message("       NIMBLE_EXTRAS_LIBS: ${NIMBLE_EXTRAS_LIBS}")
    add_definitions(-DNIMBLE_HAVE_EXTRAS)
    set(NIMBLE_HAVE_EXTRAS TRUE)
  else()
    message(FATAL_ERROR "\n**** Error:  Expected NIMBLE_EXTRAS_DIR.\n")
    set(NIMBLE_EXTRAS_SOURCES )
    set(NIMBLE_EXTRAS_LIBS )
  endif()
endif()

# Qthreads library dependencies
IF(HAVE_QTHREADS)
  IF(QTHREADS_INCLUDE_DIR AND QTHREADS_LIB_DIR)
    MESSAGE("-- Compiling with Qthreads:")
    MESSAGE("       QTHREADS_INCLUDE_DIR: ${QTHREADS_INCLUDE_DIR}")
    MESSAGE("       QTHREADS_LIB_DIR: ${QTHREADS_LIB_DIR}")
    ADD_DEFINITIONS(-DNIMBLE_HAVE_QTHREADS)
    SET(NIMBLE_HAVE_QTHREADS TRUE)
    include_directories(${QTHREADS_INCLUDE_DIR})
    link_directories(${QTHREADS_LIB_DIR})
    set(Qthreads_LIBS qthread)
  ELSE()
    MESSAGE("-- Qthreads is NOT enabled.")
    set(Qthreads_LIBS )
  ENDIF()
ENDIF()

# Optional Kokkos dependency
if(NOT HAVE_TRILINOS)
  if(HAVE_KOKKOS)
    if(KOKKOS_ROOT_DIR)
      message("-- Compiling with Kokkos")
      add_subdirectory(${KOKKOS_ROOT_DIR} ./kokkos)
      include_directories(${Kokkos_INCLUDE_DIRS_RET})
      set(NIMBLE_KOKKOS_LIBS kokkos)
      add_definitions(-DNIMBLE_HAVE_KOKKOS)
      set(NIMBLE_HAVE_KOKKOS TRUE)
    else()
      find_package(Kokkos REQUIRED)
      set(NIMBLE_KOKKOS_LIBS ${Kokkos_LIBRARIES} ${Kokkos_TPL_LIBRARIES})
      add_definitions(-DNIMBLE_HAVE_KOKKOS)
      set(NIMBLE_HAVE_KOKKOS TRUE)
      MESSAGE("-- Compiling with Kokkos:")
      MESSAGE("       Kokkos_DIR: ${Kokkos_DIR}")
      MESSAGE("       Kokkos_LIBRARIES: ${Kokkos_LIBRARIES}")
      MESSAGE("       Kokkos_TPL_LIBRARIES: ${Kokkos_TPL_LIBRARIES}")
      MESSAGE("       Kokkos_CXX_FLAGS: ${Kokkos_CXX_FLAGS}")
    endif()
    # set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Kokkos_CXX_FLAGS}")
    set (CMAKE_LD_FLAGS "${CMAKE_LD_FLAGS} ${Kokkos_LD_FLAGS}")
  else()
    message("-- Kokkos is NOT enabled.")
    set(NIMBLE_HAVE_KOKKOS FALSE)
    set(NIMBLE_KOKKOS_LIBS)
  endif()
endif()

# Exodus library dependencies
IF(NOT HAVE_TRILINOS AND NOT HAVE_NIMBLE_EXTRAS)
  SET(EXODUS_CONFIG_DIR "" CACHE PATH "Config include directory for ExodusII")
  SET(EXODUS_INCLUDE_DIR "" CACHE PATH "Include directory for ExodusII")
  SET(EXODUS_LIB_DIR "" CACHE PATH "Installed library directory for ExodusII")
  IF(EXODUS_INCLUDE_DIR AND EXODUS_LIB_DIR)
    MESSAGE("-- Compiling with Exodus:")
    MESSAGE("       EXODUS_CONFIG_DIR: ${EXODUS_CONFIG_DIR}")
    MESSAGE("       EXODUS_INCLUDE_DIR: ${EXODUS_INCLUDE_DIR}")
    MESSAGE("       EXODUS_LIB_DIR: ${EXODUS_LIB_DIR}")
    ADD_DEFINITIONS(-DNIMBLE_HAVE_EXODUS)
    SET(NIMBLE_HAVE_EXODUS TRUE)
    include_directories(${EXODUS_INCLUDE_DIR} ${EXODUS_CONFIG_DIR})
    link_directories(${EXODUS_LIB_DIR})
    set(Exodus_LIBS exodus netcdf)
#    set(Exodus_LIBS charm_kv darma_charm_backend exodus netcdf hdf5_hl hdf5 z)
  ELSE()
    MESSAGE("-- EXODUS is NOT enabled.")
    set(Exodus_LIBS )
  ENDIF()
ENDIF()

IF(CRAY)
  set(Exodus_LIBS ${Exodus_LIBS} hdf5_hl hdf5 z)
ENDIF()

include_directories(src)
include_directories(src/mpi_buckets/dist_hash)
include_directories(src/mpi_buckets/mock)
include_directories(src/mpi_buckets/src)

add_subdirectory(src)
add_subdirectory(test)
add_subdirectory(examples)

